﻿namespace StereoKit.Framework
{
	public class ThemeEditor : IStepper
	{
		class Theme
		{
			public UISettings settings;
			public Color[]    colors;

			public Theme Clone() => new Theme
			{
				settings = settings,
				colors = (Color[])colors.Clone()
			};

			public void Apply()
			{
				UI.Settings = settings;
				for (int i = 0; i < colors.Length; i++)
					UI.SetThemeColor((UIColor)i, colors[i]);
			}

			public void UpdateColor(UIColor colorType, Color gammaColor)
			{
				colors[(int)(colorType == UIColor.Max ? UIColor.Primary : colorType)] = gammaColor;
				if (colorType == UIColor.Max)
				{
					UI.ColorScheme = gammaColor;
					for (int i = 0; i < colors.Length; i++)
						colors[i] = UI.GetThemeColor((UIColor)i);
				}
				else
					UI.SetThemeColor(colorType, gammaColor);
			}

			public string ToCode()
			{
				Color primary    = UI.GetThemeColor(UIColor.Primary);
				Color background = UI.GetThemeColor(UIColor.Background);
				Color common     = UI.GetThemeColor(UIColor.Common);
				Color complement = UI.GetThemeColor(UIColor.Complement);
				Color text       = UI.GetThemeColor(UIColor.Text);
				return @$"// Theme code generated by theme editor!
UI.Settings = new UISettings
{{
	margin   = {settings.margin:0.000}f,
	padding  = {settings.padding:0.000}f,
	gutter   = {settings.gutter:0.000}f,
	depth    = {settings.depth:0.000}f,
	rounding = {settings.rounding:0.000}f
}};
UI.SetThemeColor(UIColor.Primary,    new Color({primary.r   :0.000}f,{primary.g   :0.000}f,{primary.b   :0.000}f));
UI.SetThemeColor(UIColor.Background, new Color({background.r:0.000}f,{background.g:0.000}f,{background.b:0.000}f));
UI.SetThemeColor(UIColor.Common,     new Color({common.r    :0.000}f,{common.g    :0.000}f,{common.b    :0.000}f));
UI.SetThemeColor(UIColor.Complement, new Color({complement.r:0.000}f,{complement.g:0.000}f,{complement.b:0.000}f));
UI.SetThemeColor(UIColor.Text,       new Color({text.r      :0.000}f,{text.g      :0.000}f,{text.b      :0.000}f));
";
			}

			public static Theme FromCurrent()
			{
				Theme result = new Theme();
				result.settings = UI.Settings;
				result.colors   = new Color[(int)UIColor.Max];
				for (int i = 0; i < result.colors.Length; i++)
					result.colors[i] = UI.GetThemeColor((UIColor)i);
				return result;
			}
		}

		public bool Enabled { get; set; } = true;

		Pose    settingsPose  = Pose.Identity;
		UIColor currColor     = UIColor.Primary;

		Theme active;
		Theme applied;
		Theme initial;

		public bool Initialize()
		{
			initial      = Theme.FromCurrent();
			active       = initial.Clone();
			applied      = initial.Clone();
			settingsPose = UI.PopupPose();
			return true;
		}

		public void Shutdown()
		{
		}

		public void Step()
		{
			applied.Apply();
			UI.WindowBegin("SK Theme Editor", ref settingsPose, new Vec2(56, 0) * U.cm);

			UI.LayoutPushCut(UICut.Left, 0.2f);
			Vec2 size = new Vec2(0.08f, 0);
			UI.Label("Spacing");

			UI.PanelBegin();
			UI.Label("Margin", size);   UI.SameLine();
			UI.HSlider("sl_margin",   ref active.settings.margin,   0, 40 * U.mm, 0.001f);
			UI.Label("Padding", size);  UI.SameLine();
			UI.HSlider("sl_padding",  ref active.settings.padding,  0, 40 * U.mm, 0.001f);
			UI.Label("Gutter", size);   UI.SameLine();
			UI.HSlider("sl_gutter",   ref active.settings.gutter,   0, 40 * U.mm, 0.001f);
			UI.Label("Depth", size);    UI.SameLine();
			UI.HSlider("sl_depth",    ref active.settings.depth,    0, 40 * U.mm, 0.001f);
			UI.Label("Rounding", size); UI.SameLine();
			UI.HSlider("sl_rounding", ref active.settings.rounding, 0, 40 * U.mm, 0.001f);
			UI.PanelEnd();

			if (UI.Button("Log Theme Code")) Log.Info(active.ToCode());
			if (UI.Button("Original"))
			{
				initial.Apply();
				active  = initial.Clone();
				applied = initial.Clone();
				currColor = UIColor.Primary;
			}
			UI.SameLine();
			if (UI.Button("Apply")) applied = active.Clone();
			UI.LayoutPop();

			size = new Vec2(0.1f, 0);
			UI.Label("Color");
			if (UI.Radio("Theme (All)", currColor == UIColor.Max       , size)) { currColor = UIColor.Max;        }
			UI.SameLine();
			if (UI.Radio("Primary",     currColor == UIColor.Primary   , size)) { currColor = UIColor.Primary;    }
			UI.SameLine();
			if (UI.Radio("Background",  currColor == UIColor.Background, size)) { currColor = UIColor.Background; }
			if (UI.Radio("Common",      currColor == UIColor.Common    , size)) { currColor = UIColor.Common;     }
			UI.SameLine();
			if (UI.Radio("Complement",  currColor == UIColor.Complement, size)) { currColor = UIColor.Complement; }
			UI.SameLine();
			if (UI.Radio("Text",        currColor == UIColor.Text      , size)) { currColor = UIColor.Text;       }

			UI.Label("Hue / Saturation / Value");
			Vec3 hsv = active.colors[(int)(currColor == UIColor.Max ? UIColor.Primary : currColor)].ToHSV();
			UI.PanelBegin();

			bool colorDirty = false;
			float x = hsv.x;
			float y = hsv.y;
			float z = hsv.z;
			colorDirty = UI.HSlider("x", ref x, 0, 1, 0) || colorDirty;
			colorDirty = UI.HSlider("y", ref y, 0, 1, 0) || colorDirty;
			colorDirty = UI.HSlider("z", ref z, 0, 1, 0) || colorDirty;

			Color  color  = Color.HSV(x,y,z);
			Bounds bounds = UI.LayoutReserve(Vec2.Zero, false, 0.002f);
			Mesh.Cube.Draw(Material.Unlit, Matrix.TS(bounds.center, bounds.dimensions), color.ToLinear());

			if (colorDirty)
				active.colors[(int)(currColor == UIColor.Max ? UIColor.Primary : currColor)] = color;
			UI.PanelEnd();

			UI.WindowEnd();

			active.Apply();
		}
	}
}
